這幾天調整完基本架構
再來繼續處理特殊規格元件的部分
有時候我們會在表單裡面看到一種列表
比如說新增聯絡人
會有一個Table呈現多筆資料
也許還會有新增修刪功能
今天就要來設計一下類似這樣的元件
設計上可能會參考之前組合元件的方式
用groupName把相關的欄位綁在一起
不過這邊我們會希望這個列表會有一個可控的formArray承接
這樣在設定檔裡面會多一個inputType="list"
當碰到這個型別的時候會產生formArray
// form-input.component.ts
if (setting.groupType == 'list' && !!setting.groupName)
{
if (!this.innerForm.contains(setting.groupName))
{
let newFormArray = new FormArray([])
this.innerForm.addControl(setting.groupName, newFormArray);
this.pageSetting.form?.addControl(setting.groupName, newFormArray);
}
return
}
首先在讀取設定檔產生form的時候會多一段判斷是不是list的
這邊會在原本的邏輯之前 因為如果判斷跟list相關的欄位是連form都不會塞control的
getGroupList(group: FormGroup): string | any
{
let Result = Object.keys(group.value).map(obj =>
{
let innerControl = group.get(obj)
if (innerControl?.value !== null && typeof innerControl?.value === 'object')
{
if (Array.isArray(innerControl.value))
{
let fg = this.fb.group({});
fg.addControl(obj, innerControl);
return fg
} else
{
return innerControl
}
} else
{
return obj;
}
});
return Result;
}
getGroupList這邊也有調整
我們這次的formArray會比較接近之前的組合元件
所以是走combo-field這一塊
這樣我們會需要傳分類完的fieldSettings以及在form裡面乘載相關的FormArray
但這邊如果直接傳FormArray的話 我們可能無法得知formArray的名稱
這樣後續要取fieldSettings的話會有點困難
所以我們這邊多包一層formGroup
這樣在取設定檔的時候可以透過object.keys去取得formArray的名稱
getListSettings(formArrayName: string)
{
let listName = this.pageSetting.fieldSettings.find(f => f.name == formArrayName)?.groupName;
return this.pageSetting.fieldSettings.filter(f => f.groupName == listName);
}
這邊增加一個方法可以透過formArrayName取得相關的設定檔
// combo-field.component.html
<div *ngIf="findFieldSetting('list')">
<app-list [fieldSettings]="fieldSettings" [inputForm]="inputFormGroup">
</app-list>
</div>
這樣combo-field也不用太大變動
一樣新增list區塊
// list.component.ts
@Input() fieldSettings!: FieldSetting[];
@Input() inputForm!: any;
innerFormArray!: FormArray;
subFormGroup!: FormGroup;
titleArr!: string[];
get listKey()
{
return Object.keys(this.inputForm.value)[0]
}
get inputFormArray()
{
return this.inputForm.get(this.listKey) as FormArray
}
constructor(
private fb: FormBuilder,
private validatorService: ValidatorService
) { }
ngOnInit(): void
{
this.titleArr = [];
this.innerFormArray = new FormArray<FormGroup>([]);
this.subFormGroup = new FormGroup({});
let defaultValue!: string[];
this.fieldSettings.forEach(setting =>
{
if (setting.inputType != 'list')
{
let newControl = this.fb.control(setting.defaultValue) as FormControl;
if (setting.validator && setting.validator?.length > 0)
{
if (!!setting.validator.find(v => v == 'required')) setting.required = true;
newControl.addValidators(this.validatorService.getValidators(setting.validator));
}
this.titleArr.push(setting.cname);
this.subFormGroup.addControl(setting.name, newControl);
} else
{
defaultValue = setting.defaultValue! as string[];
}
})
defaultValue.forEach((value: any) =>
{
this.subFormGroup.reset();
this.subFormGroup.patchValue(value);
this.innerFormArray.push(this.subFormGroup);
})
this.inputFormArray.clear();
this.innerFormArray.controls.forEach((group: AbstractControl) =>
{
this.inputFormArray.push(group);
});
}
// list.component.html
<table [formGroup]="inputForm">
<thead>
<tr>
<th *ngFor="let title of titleArr">
{{ title }}
</th>
</tr>
</thead>
<tbody formArrayName="{{ listKey }}">
<tr
*ngFor="let row of inputFormArray.controls; let i = index"
[formGroupName]="i"
>
<td>
<input formControlName="list-name" />
</td>
<td>
<input formControlName="list-phone" />
</td>
<td>
<input formControlName="list-mail" />
</td>
</tr>
</tbody>
</table>
這邊我們會有個subFormGroup
透過設定檔我們會決定subFormGroup的內容
然後如果要新增 就會以subFormGroup為模板塞進innerFormArray裡面
這邊我們還沒有新增的機制
我們就加一段 如果list的設定檔裡面有defaultValue
那就按造defaultValue塞值到innerFormArray裡面
最後會再同步inputForm裡面的formArray
這次改的東西有點多
新增的部分我們明天繼續
今日程式:day24